function ReloadSniperRifleDone takes nothing returns nothing
	local timer reloadTimer = GetExpiredTimer()
	local integer timerId = GetHandleId(reloadTimer)
	local unit gunner = LoadUnitHandle(udg_HT , timerId , 3)
	local item gun = LoadItemHandle(udg_HT , timerId , 4)
	local item bullet = LoadItemHandle(udg_HT , timerId , 5)
	//--
	call PauseTimer(reloadTimer)
	call FlushChildHashtable(udg_HT , timerId)
	call DestroyTimer(reloadTimer)
	if gun != null and bullet != null and UnitHasItem(gunner , gun) and UnitHasItem(gunner , bullet) then
		if GetItemCharges(bullet) >= 10 then
			call SetItemCharges(gun , 10)
			call SetItemCharges(bullet , GetItemCharges(bullet) - 10)
		else
			call SetItemCharges(gun , GetItemCharges(bullet))
			call SetItemCharges(bullet , 0)
		endif
		if GetItemCharges(bullet) <= 0 then
			call RemoveItem(bullet)
		endif
		call PlaySoundOnUnit(gunner , "clipin.wav")
	endif
	call SetItemDroppable(gun , true)
	call SetItemDroppable(bullet , true)
	call SaveBoolean(udg_UnitDataHashTable , GetHandleId(gunner) , StringHash("RELOADING") , false)
	//--
	set gun = null
	set bullet = null
	set gunner = null
	set reloadTimer = null
endfunction

function ReloadSniperRifle takes unit gunner returns nothing
	local item gun = GetItemOfTypeFromUnitBJ(gunner , 'I00F')
	local item bullet  = GetItemOfTypeFromUnitBJ(gunner , 'I00G')
	local player gunnerOwner = GetOwningPlayer(gunner)
	local boolean reloading = LoadBoolean(udg_UnitDataHashTable , GetHandleId(gunner) , StringHash("RELOADING"))
	local timer reloadTimer = null
	local integer timerId = 0
	//--
	if gun != null and bullet != null and not reloading and GetItemCharges(gun) < 10 then
		call SetItemDroppable(gun , false)
		call SetItemDroppable(bullet , false)	
		call SaveBoolean(udg_UnitDataHashTable , GetHandleId(gunner) , StringHash("RELOADING") , true)
		call SetItemCharges(gun , 0)
		set reloadTimer = CreateTimer()
		set timerId = GetHandleId(reloadTimer)
		call SaveUnitHandle(udg_HT , timerId , 3 , gunner)
		call SaveItemHandle(udg_HT , timerId , 4 , gun)
		call SaveItemHandle(udg_HT , timerId , 5 , bullet)
		call TimerStart(reloadTimer , 3.0 , false , function ReloadSniperRifleDone)
		call DisplayTimedTextToPlayer(gunnerOwner , 0 , 0 , 2.0 , "更換彈夾中....")
		call PlaySoundOnUnit(gunner , "clipout.wav")
	endif
	//--
	set gun = null
	set bullet = null
	set gunnerOwner = null
	set reloadTimer = null
endfunction

function SniperRifleBulletDamage takes nothing returns nothing
	local unit target = GetEnumUnit()
	//--
	if IsUnitEnemy(target , udg_TempPlayer) and IsUnitInRangeLoc(target , udg_TempLocation , udg_TempRadius) and not IsUnitType(target , UNIT_TYPE_STRUCTURE) and GetUnitState(target , UNIT_STATE_LIFE) > 0.0 and not HaveSavedBoolean(udg_TempHashTable , GetHandleId(target) , 3) then
		call UnitDamageTarget(udg_TempDamager , target , udg_TempDamage , true , false , ATTACK_TYPE_NORMAL, DAMAGE_TYPE_COLD , WEAPON_TYPE_METAL_MEDIUM_BASH)
		call SaveBoolean(udg_TempHashTable , GetHandleId(target) , 3 , true)
	endif
	//--
	set target = null
endfunction

function SniperRifleBulletRoutine takes nothing returns nothing
	local timer bulletTimer = GetExpiredTimer()
	local integer timerId = GetHandleId(bulletTimer)
	local unit bulletEffect = LoadUnitHandle(udg_HT , timerId , 3)
	local real dx = LoadReal(udg_HT , timerId , 4)
	local real dy = LoadReal(udg_HT , timerId , 5)
	local real process = LoadReal(udg_HT , timerId , 6)
	local hashtable hitHashtable = LoadHashtableHandle(udg_HT , timerId , 7)
	local boolean end = false
	//--
	//造成傷害
	set udg_TempDamager = bulletEffect
	set udg_TempPlayer = GetOwningPlayer(bulletEffect)
	set udg_TempDamage = 300.0
	set udg_TempRadius = 50.0
	set udg_TempLocation = GetUnitLoc(bulletEffect)
	set udg_TempHashTable = hitHashtable
	set bj_wantDestroyGroup = true
	call ForGroupBJ(GetUnitsInRangeOfLocMatching(udg_TempRadius+70.0, udg_TempLocation , null) , function SniperRifleBulletDamage)
	call RemoveLocation(udg_TempLocation)
	//移動子彈
	if process < 100.0 then
		set process = process + 1.0
		call SaveReal(udg_HT , timerId , 6 , process)
		call SetUnitX(bulletEffect , GetUnitX(bulletEffect) + dx)
		call SetUnitY(bulletEffect , GetUnitY(bulletEffect) + dy)
	else
		set end = true
	endif
	if end then
		call PauseTimer(bulletTimer)
		call FlushChildHashtable(udg_HT , timerId)
		call DestroyTimer(bulletTimer)
		call KillUnit(bulletEffect)
		call RemoveUnit(bulletEffect)
		call FlushParentHashtable(hitHashtable)
	endif
	//--
	set bulletTimer = null
	set bulletEffect = null
	set hitHashtable = null
endfunction

function Trig_SniperRifle_Effect takes nothing returns nothing
	local unit gunner = GetTriggerUnit()
	local player gunnerOwner = GetOwningPlayer(gunner)
	local location gunnerLocation = GetUnitLoc(gunner)
	local location targetLocation = GetSpellTargetLoc()
	local item gun = GetItemOfTypeFromUnitBJ(gunner , 'I00F')
	local real angle = AngleBetweenPoints(gunnerLocation , targetLocation)
	local real delta = 2500.0 * 0.01 // speed setting
	local real dx = Cos(angle * bj_DEGTORAD) * delta
	local real dy = Sin(angle * bj_DEGTORAD) * delta
	local unit bulletEffect = CreateUnit(gunnerOwner , 'e003' , GetLocationX(gunnerLocation) , GetLocationY(gunnerLocation) , angle)
	local hashtable hitHashtable = InitHashtable()
	local timer bulletTimer = CreateTimer()
	local integer timerId = GetHandleId(bulletTimer)
	//--
	call SetUnitX(bulletEffect , GetLocationX(gunnerLocation) + dx)
	call SetUnitY(bulletEffect , GetLocationY(gunnerLocation) + dy)
	call SetItemCharges(gun , GetItemCharges(gun) - 1)
	call SaveUnitHandle(udg_HT , timerId , 3 , bulletEffect)
	call SaveReal(udg_HT , timerId , 4 , dx)
	call SaveReal(udg_HT , timerId , 5 , dy)
	call SaveReal(udg_HT , timerId , 6 , 0.0)
	call SaveHashtableHandle(udg_HT , timerId , 7 , hitHashtable)
	call TimerStart(bulletTimer , 0.01 , true , function SniperRifleBulletRoutine)
	if GetItemCharges(gun) <= 0 then
		call ReloadSniperRifle(gunner)
	endif
	//聲音
	call PlaySoundOnUnit(gunner , "Units\\Human\\Rifleman\\RiflemanAttack1.wav")
	call UnitPlayAnimation(gunner , 149 , 2.0 , 0.4)
	//--
	set gunner = null
	set gunnerOwner = null
	call RemoveLocation(gunnerLocation)
	set gunnerLocation = null
	call RemoveLocation(targetLocation)
	set targetLocation = null
	set gun = null
	set bulletEffect = null
	set bulletTimer = null
endfunction

function Trig_SniperRifle_Actions takes nothing returns nothing
	local unit gunner = GetTriggerUnit()
	local integer gunnerId = GetHandleId(gunner)
	local player gunnerOwner = GetOwningPlayer(gunner)
	local item gun = GetItemOfTypeFromUnitBJ(gunner , 'I00F')
	local integer gunCharge = GetItemCharges(gun)
	local item bullet = GetItemOfTypeFromUnitBJ(gunner , 'I00G')
	local boolean reloading = LoadBoolean(udg_UnitDataHashTable , gunnerId , StringHash("RELOADING"))
	//--	
	if gun == null then
		call UnitRemoveAbility(gunner , 'A015')
	elseif reloading then
		call IssueImmediateOrderById(gunner , 851972) //停止
		call DisplayTimedTextToPlayer(gunnerOwner, 0 , 0 , 1.0 , "更換彈夾中")
	elseif gunCharge <= 0 then
		call IssueImmediateOrderById(gunner , 851972) //停止
		if bullet == null then
			call DisplayTimedTextToPlayer(gunnerOwner, 0 , 0 , 2.0 , "沒彈藥了")
		else
			call ReloadSniperRifle(gunner)
		endif
	endif
	//--
	set gunner = null
	set gunnerOwner = null
	set gun = null
	set bullet = null
endfunction

function Trig_SniperRifle_Conditions takes nothing returns boolean
	return GetSpellAbilityId() == 'A015'
endfunction

function InitTrig_SniperRifle takes nothing returns nothing
	local trigger sniperRifleEffectTrigger = CreateTrigger()
	//--
	set gg_trg_SniperRifle = CreateTrigger()
	call TriggerRegisterAnyUnitEventBJ(gg_trg_SniperRifle, EVENT_PLAYER_UNIT_SPELL_CHANNEL)
	call TriggerAddCondition(gg_trg_SniperRifle, Condition(function Trig_SniperRifle_Conditions))
	call TriggerAddAction(gg_trg_SniperRifle, function Trig_SniperRifle_Actions)
	
	call TriggerRegisterAnyUnitEventBJ(sniperRifleEffectTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT)
	call TriggerAddCondition(sniperRifleEffectTrigger, Condition(function Trig_SniperRifle_Conditions))
	call TriggerAddAction(sniperRifleEffectTrigger, function Trig_SniperRifle_Effect)
endfunction